package com.chaoxi.picturebackend.manager;

import cn.hutool.json.JSONObject;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.chaoxi.picturebackend.properties.AliOssProperties;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;

/**
 * 通用OSS文件管理工具类
 * 负责基础的OSS文件操作，与具体业务解耦
 */
@Slf4j
@AllArgsConstructor
@Component
public class OSSManager {
    @Resource
    private AliOssProperties ossProperties;
    
    public String getEndpoint() {
        return ossProperties.getEndpoint();
    }
    
    public String getBucketName() {
        return ossProperties.getBucketName();
    }

    /**
     * 通用文件上传
     *
     * @param bytes 文件字节数组
     * @param objectName OSS对象名称
     * @return 文件访问URL
     */
    public String upload(byte[] bytes, String objectName) {
        String endpoint = ossProperties.getEndpoint();
        String bucketName = ossProperties.getBucketName();

        OSS ossClient = createOSSClient();
        try {
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
            String url = buildFileUrl(bucketName, endpoint, objectName);
            log.info("文件上传成功: {}", url);
            return url;
        } catch (OSSException oe) {
            logError("上传文件失败", oe);
            throw new RuntimeException("OSS上传失败", oe);
        } catch (ClientException ce) {
            logError("客户端异常", ce);
            throw new RuntimeException("OSS客户端异常", ce);
        } finally {
            shutdownOSSClient(ossClient);
        }
    }

    /**
     * 通用文件上传
     *
     * @param objectName OSS对象名称
     * @param file 文件
     * @return 文件访问URL
     */
    public String upload(String objectName,File file) {
        String endpoint = ossProperties.getEndpoint();
        String bucketName = ossProperties.getBucketName();

        OSS ossClient = createOSSClient();
        try {
            ossClient.putObject(bucketName, objectName, file);
            String url = buildFileUrl(bucketName, endpoint, objectName);
            return url;
        } catch (OSSException oe) {
            logError("上传文件失败", oe);
            throw new RuntimeException("OSS上传失败", oe);
        } catch (ClientException ce) {
            logError("客户端异常", ce);
            throw new RuntimeException("OSS客户端异常", ce);
        } finally {
            shutdownOSSClient(ossClient);
        }
    }


    /**
     * 文件下载
     *
     * @param objectName OSS对象名称
     * @return 文件字节数组
     */
    public byte[] download(String objectName) {
        String bucketName = ossProperties.getBucketName();
        OSS ossClient = createOSSClient();
        OSSObject ossObject = null;

        try {
            // 先检查对象是否存在
            if (!ossClient.doesObjectExist(bucketName, objectName)) {
                throw new RuntimeException("文件不存在: " + objectName);
            }

            ossObject = ossClient.getObject(bucketName, objectName);
            try (InputStream inputStream = ossObject.getObjectContent()) {
                return inputStream.readAllBytes();
            }
        } catch (OSSException oe) {
            logError("下载文件失败", oe);
            // 记录具体的错误代码和消息
            throw new RuntimeException("OSS下载失败: " + oe.getErrorCode() + " - " + oe.getErrorMessage(), oe);
        } catch (ClientException ce) {
            logError("客户端异常", ce);
            throw new RuntimeException("OSS客户端异常: " + ce.getMessage(), ce);
        } catch (IOException e) {
            log.error("读取文件内容失败: {}", e.getMessage(), e);
            throw new RuntimeException("IO异常: " + e.getMessage(), e);
        } finally {
            closeResources(ossObject, ossClient);
        }
    }

    /**
     * 获取基本图片信息 Json
     * @param pictureName 图片文件名
     * @return JSONObject
     * @throws IOException IO异常
     */
    public JSONObject getBasicInfoPictureJson(String pictureName) throws IOException {
        return getPictureJson(pictureName, "image/info");
    }

    /**
     * 获取图片主色调
     * @param pictureName 图片文件名
     * @return JSONObject
     * @throws IOException IO异常
     */
    public JSONObject getColorInfoPictureJson(String pictureName) throws IOException {
        return getPictureJson(pictureName, "image/average-hue");
    }

    /**
     * 获取图片的元数据信息并返回JSON对象
     *
     * @param pictureName 图片文件名
     * @param process 图片处理参数
     * @return 包含图片元数据信息的JSONObject对象
     * @throws IOException 当读取图片数据发生IO异常时抛出
     */
    public JSONObject getPictureJson(String pictureName, String process) throws IOException {
        String bucketName = ossProperties.getBucketName();
        OSS ossClient = createOSSClient();
        GetObjectRequest request = new GetObjectRequest(bucketName, pictureName);
        // 设置图片处理参数
        request.setProcess(process);

        OSSObject objectResult = null;
        try {
            // 先检查对象是否存在
            if (!ossClient.doesObjectExist(bucketName, pictureName)) {
                throw new IOException("图片文件不存在: " + pictureName);
            }
            
            objectResult = ossClient.getObject(request);

            // 读取图片数据到字节数组输出流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = objectResult.getObjectContent().read(buffer)) != -1) {
                baos.write(buffer, 0, bytesRead);
            }

            // 解析图片元数据
            String imageInfo = baos.toString("UTF-8");
            
            // 检查返回的内容是否是有效的JSON格式（以 '{' 开头）
            if (imageInfo == null || imageInfo.trim().isEmpty() || !imageInfo.trim().startsWith("{")) {
                log.error("获取到的图片元数据不是有效的JSON格式: {}", imageInfo);
                throw new IOException("获取图片元数据失败：返回内容不是有效的JSON格式");
            }
            
            return new JSONObject(imageInfo);
        } catch (OSSException oe) {
            log.error("获取图片元数据失败 - 错误代码: {}, 错误消息: {}, 请求ID: {}, 图片名称: {}",
                    oe.getErrorCode(), oe.getErrorMessage(), oe.getRequestId(), pictureName);
            // 特殊处理文件损坏的情况
            if ("Input image file may be corrupted.".equals(oe.getErrorMessage())) {
                throw new IOException("图片文件已损坏或格式不正确: " + pictureName, oe);
            }
            // 特殊处理不支持的图片格式
            if ("This image format is not supported.".equals(oe.getErrorMessage())) {
                throw new IOException("不支持的图片格式: " + pictureName, oe);
            }
            // 特殊处理文件不存在的情况
            if ("NoSuchKey".equals(oe.getErrorCode()) || "The specified key does not exist.".equals(oe.getErrorMessage())) {
                throw new IOException("图片文件不存在: " + pictureName, oe);
            }
            throw new IOException("获取图片元数据失败", oe);
        } catch (ClientException ce) {
            logError("客户端异常", ce);
            throw new IOException("客户端异常", ce);
        } finally {
            closeResources(objectResult, ossClient);
        }
    }


    /**
     * 删除文件
     *
     * @param objectName OSS对象名称
     */
    public void delete(String objectName) {
        String bucketName = ossProperties.getBucketName();
        OSS ossClient = createOSSClient();

        try {
            ossClient.deleteObject(bucketName, objectName);
            log.info("文件删除成功: {}", objectName);
        } catch (OSSException oe) {
            logError("删除文件失败", oe);
            throw new RuntimeException("文件删除失败", oe);
        } catch (ClientException ce) {
            logError("客户端异常", ce);
            throw new RuntimeException("OSS客户端异常", ce);
        } finally {
            shutdownOSSClient(ossClient);
        }
    }

    /**
     * 检查文件是否存在
     *
     * @param objectName OSS对象名称
     * @return 是否存在
     */
    public boolean exists(String objectName) {
        String bucketName = ossProperties.getBucketName();
        OSS ossClient = createOSSClient();

        try {
            return ossClient.doesObjectExist(bucketName, objectName);
        } catch (OSSException oe) {
            logError("检查文件存在性失败", oe);
            return false;
        } catch (ClientException ce) {
            logError("客户端异常", ce);
            return false;
        } finally {
            shutdownOSSClient(ossClient);
        }
    }

    /**
     * 获取文件信息
     *
     * @param objectName OSS对象名称
     * @return 文件元数据
     */
    public ObjectMetadata getFileMetadata(String objectName) {
        String bucketName = ossProperties.getBucketName();
        OSS ossClient = createOSSClient();

        try {
            return ossClient.getObjectMetadata(bucketName, objectName);
        } catch (OSSException oe) {
            logError("获取文件元数据失败", oe);
            throw new RuntimeException("获取文件信息失败", oe);
        } catch (ClientException ce) {
            logError("客户端异常", ce);
            throw new RuntimeException("OSS客户端异常", ce);
        } finally {
            shutdownOSSClient(ossClient);
        }
    }

    // ============ 私有方法 ============

    private OSS createOSSClient() {
        return new OSSClientBuilder().build(
                ossProperties.getEndpoint(),
                ossProperties.getAccessKeyId(),
                ossProperties.getAccessKeySecret()
        );
    }

    private void shutdownOSSClient(OSS ossClient) {
        if (ossClient != null) {
            ossClient.shutdown();
        }
    }

    private void closeResources(OSSObject ossObject, OSS ossClient) {
        if (ossObject != null) {
            try {
                ossObject.close();
            } catch (Exception e) {
                log.warn("关闭OSS对象失败", e);
            }
        }
        shutdownOSSClient(ossClient);
    }

    private String buildFileUrl(String bucketName, String endpoint, String objectName) {
        return String.format("https://%s.%s/%s",
                bucketName, stripProtocol(endpoint), objectName);
    }

    private String stripProtocol(String endpoint) {
        if (endpoint.startsWith("http://")) {
            return endpoint.substring(7);
        } else if (endpoint.startsWith("https://")) {
            return endpoint.substring(8);
        }
        return endpoint;
    }

    private void logError(String operation, OSSException oe) {
        log.error("{} - OSS异常: Error Message: {}, Error Code: {}, Request ID: {}",
                operation, oe.getErrorMessage(), oe.getErrorCode(), oe.getRequestId());
    }

    private void logError(String operation, ClientException ce) {
        log.error("{} - 客户端异常: Error Message: {}", operation, ce.getMessage());
    }
}